import java_cup.runtime.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

%%  
 
 
%class LexicoAda  
%line
%column
%unicode
%cup

%{
private StringBuffer stringBuffer = new StringBuffer();
	
	private Symbol symbol(int type) {
		return symbol(type, yytext());
	}
	
	private Symbol symbol(int type, String typename, String value, String info) {
		if (type == sym.EOF)
			System.out.printf ("Encontrado %s (%d), que é: %s\n", typename, type, info);
		else
			System.out.printf ("Encontrado `%s`, token do tipo %s (%d), que é: %s\n", value, typename, type, info);
		
		Object valueToCup = value;
		if (typename.equals("numinteger")) 
			valueToCup = Integer.valueOf(value);
		else if (typename.equals("numoctal"))
			valueToCup = Integer.parseInt(value.substring(0, value.length() - 2), 8);
		else if (typename.equals("numhexadecimal"))
			valueToCup = Integer.parseInt(value.substring(0, value.length() - 2), 16);
		else if (typename.equals("numreal"))
			valueToCup = Double.valueOf(value);
		
		return new Symbol(type, yyline, yycolumn, valueToCup);
	}
	
	private String ConfirmIfIsNumber() {
	
		String foundToken = yytext();
		
		Pattern pattern = Pattern.compile("[_a-zA-Z]");
		Matcher matcher = pattern.matcher(String.valueOf(yycharat(yylength())));
		
		if (matcher.find())
			throw new RuntimeException("Erro Lexico na linha "+ (yyline+1) +", coluna "+ (yychar+1) +": Identificador ou nome de procedimento inválido");
			
		return foundToken;
	}
	
	private Symbol symbol(int type, Object val) {
		return new Symbol(type, yyline, yycolumn, val);
	}

	public int getLine() {
		return yyline; 
	}

	public int getColumn() {
		return yycolumn;
	}

	public boolean hasNext() {
		return !zzAtEOF;
  	}
  	
	private void error(String message) {
		throw new RuntimeException("Erro Lexico na linha "+ (yyline+1) +", coluna "+ (yychar+1) +": " + message);
	}

	public String toString(){
		return yytext();
	}
	
	public Boolean scannerIsAtEof() {
		return this.zzAtEOF;
	}
%}




digit = [0-9]
upper_case_letter = [A-Z]
lower_case_letter = [a-z]
extended_digit = {digit} | "A" | "B" | "C" | "D" | "E" | "F" 
line_terminator = \r| \n | \r\n
format_effector = \t | \v | \r | \f 

identifier_letter = {upper_case_letter} | {lower_case_letter}
identifier = {identifier_letter}  (["_"]? ( {identifier_letter} | {digit}) )* 

numeral = {digit} ( [ "_" ]? { digit } )* 
exponent = ( "E" [ "+" ]? {numeral} ) | ( "E-" {numeral} )  
graphic_character = {identifier_letter} | {digit} | " " | [^\n\r\"\\]
character = {graphic_character}   | {format_effector} //| "other control function" 
based_numeral = {extended_digit} ( [ "_" ]? {extended_digit} )*

//comment = "--" {character}* {line_terminator}
comment_start = "--"
comment_end = "\n" | "<<EOF>>"

whitespace      = [ \n\t]

%state COMMENT

%% 

//{comment}  {System.out.println("IIIIIIIIIIIIIIRU");}
//"<<"		{ return symbol(sym.); }
//"<>"		{ return symbol(sym.); }
//"=>"		{ return symbol(sym.AND); }
//">>"		{ return symbol(sym.AND); }


<YYINITIAL> {

{comment_start}  { yybegin(COMMENT); }

"**"		{return symbol(sym.EXP,	"Exponent", yytext(), "**"); 	 }
".."		{ return symbol(sym.RANGE_SEP,	"Range Separator", yytext(), ".."); }
"/="		{ return symbol(sym.NOT_EQ,	"Not equal", yytext(), "/="); }
"<="		{ return symbol(sym.LESS_EQ,	"Less or equal", yytext(), "<=");  }
">="		{ return symbol(sym.GTR_EQ,	"Greater or equal", yytext(), ">=");  }
":="		{ return symbol(sym.ASSMNT,	"Assignment", yytext(), ":=");  }
"#"			{ return symbol(sym.HASH,	"Hash", yytext(), "#");  }
"&"			{ return symbol(sym.AMPERSAND,	"Ampersand", yytext(), "&");  }
"*"			{ return symbol(sym.TIMES,	"Times", yytext(), "*");  }
"+"			{ return symbol(sym.PLUS,	"Plus", yytext(), "+");  }
"-"			{ return symbol(sym.MINUS,	"Minus", yytext(), "-");  }
"'"			{ return symbol(sym.SINGLE_MARK,	"Single Quotation Mark", yytext(), "'");  }
"."			{ return symbol(sym.DOT,	"Dot", yytext(), ".");  }
"/"			{ return symbol(sym.DIVIDE,	"Divide", yytext(), "/");  }
"<"			{ return symbol(sym.LESS,	"Less", yytext(), "<");  }
"="			{ return symbol(sym.EQ,	"Equal", yytext(), "=");  }
">"			{ return symbol(sym.GTR,	"Greater", yytext(), ">");  }
"|"			{ return symbol(sym.PIPELINE,	"Pipeline", yytext(), "|");  }
"_"			{ return symbol(sym.UNDERSCORE,	"Underscore", yytext(), "_");  }
":"			{ return symbol(sym.COLON,	"Colon", yytext(), ":");  }
","			{ return symbol(sym.COMMA,	"Comma", yytext(), ",");  }
"("			{ return symbol(sym.LEFT_PAREN,	"Left Parenthesis", yytext(), "(");  }
")"			{ return symbol(sym.RIGHT_PAREN,	"Rigth Parenthesis", yytext(), ")");  }
";"			{ return symbol(sym.SEMI,	"Semi", yytext(), ";");  }
"\""		{ return symbol(sym.QT_MARK,	"Quotation Mark", yytext(), "''");  }
"abort"			{ return symbol(sym.ABORT,	"Abort", yytext(), "Keyword");}
"abs"			{ return symbol(sym.ABS,	"abs", yytext(), "Keyword");}
"access"		{ return symbol(sym.ACCESS,	"access", yytext(), "Keyword");}
"and"			{ return symbol(sym.AND,	"AND", yytext(), "Keyword");}
"begin"			{ return symbol(sym.BEGIN,	"begin", yytext(), "Keyword");}
"case"			{ return symbol(sym.CASE,	"case", yytext(), "Keyword");}
"constant"		{ return symbol(sym.CONSTANT,	"constant", yytext(), "Keyword");}
"do"			{ return symbol(sym.DO,	"do", yytext(), "Keyword");}
"else"			{ return symbol(sym.ELSE,	"else", yytext(), "Keyword");}
"elseif"		{ return symbol(sym.ELSEIF,	"elseif", yytext(), "Keyword");}
"end of line"	{ return symbol(sym.END_OF_LINE,	"end of line", yytext(), "Keyword");}
"end"			{ return symbol(sym.END,	"end", yytext(), "Keyword");}
"exception"		{ return symbol(sym.EXCEPTION,	"exception", yytext(), "Keyword");}
"exit"			{ return symbol(sym.EXIT,	"exit", yytext(), "Keyword");}
"for"			{ return symbol(sym.FOR,	"for", yytext(), "Keyword");}
"function"		{ return symbol(sym.FUNCTION,	"function", yytext(), "Keyword");}
"goto"			{ return symbol(sym.GOTO,	"goto", yytext(), "Keyword");}
"if"			{ return symbol(sym.IF,	"if", yytext(), "Keyword");}
"in"			{ return symbol(sym.IN,	"in", yytext(), "Keyword");}
"is"			{ return symbol(sym.IS,	"is", yytext(), "Keyword");}
"loop"			{ return symbol(sym.LOOP,	"loop", yytext(), "Keyword");}
"mod"			{ return symbol(sym.MOD,	"mod", yytext(), "Keyword");}
"not"			{ return symbol(sym.NOT,	"not", yytext(), "Keyword");}
"null"			{ return symbol(sym.NULL,	"null", yytext(), "Keyword");}
"or"			{ return symbol(sym.OR,	"or", yytext(), "Keyword");}
"others"		{ return symbol(sym.OTHERS,	"others", yytext(), "Keyword");}
"out"			{ return symbol(sym.OUT,	"out", yytext(), "Keyword");}
"procedure" 	{ return symbol(sym.PROCEDURE,	"procedure", yytext(), "Keyword");}
"raise" 		{ return symbol(sym.RAISE,	"raise", yytext(), "Keyword");}
"record" 		{ return symbol(sym.RECORD,	"record", yytext(), "Keyword");}
"rem" 			{ return symbol(sym.REM,	"rem", yytext(), "Keyword");}
"return" 		{ return symbol(sym.RETURN,	"return", yytext(), "Keyword");}
"reverse" 		{ return symbol(sym.REVERSE,	"reverse", yytext(), "Keyword");}
"then" 			{ return symbol(sym.THEN,	"then", yytext(), "Keyword");}
"when" 			{ return symbol(sym.WHEN,	"when", yytext(), "Keyword");}
"while" 		{ return symbol(sym.WHILE,	"while", yytext(), "Keyword");}
"xor" 			{ return symbol(sym.XOR,	"xor", yytext(), "Keyword");}
"Range" 		{ return symbol(sym.CAPS_RANGE,	"range", yytext(), "Keyword");}
//<<EOF>> 		{ return symbol(sym.EOF,	"eof", yytext(), "Keyword");}

{whitespace} {}

{identifier} {return  symbol( sym.IDENTIFIER, "IDENTIFIER", yytext(), "Identificador"); }
{numeral} {String foundToken = ConfirmIfIsNumber(); return  symbol( sym.NUMERAL, "NUMERAL", foundToken, "Literal"); }
{character} {return  symbol( sym.CHARACTER, "CHARACTER", yytext(), "Literal"); }
{exponent} {String foundToken = ConfirmIfIsNumber(); return  symbol( sym.EXPONENT, "EXPONENT", foundToken, "Literal"); }
{based_numeral} {String foundToken = ConfirmIfIsNumber(); return  symbol( sym.BASED_NUMERAL, "BASED_NUMERAL", foundToken, "Literal"); }
. { System.out.println("Illegal char, '" + yytext() +"' line: " + yyline + ", column: " + yychar); }

}

<COMMENT> {
	{comment_end}	{yybegin(YYINITIAL);}	
	[^] 		{ }
}